package org.admin.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import core.data.DataHandle;
import org.admin.entity.domain.App;
import org.admin.entity.domain.Menu;
import org.admin.entity.domain.PermsGroup;
import org.admin.entity.dto.MenuDto;
import org.admin.entity.vo.MenuFetchVo;
import org.admin.entity.vo.MenuQueryVo;
import org.admin.mapper.MenuMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class MenuService {
    @Autowired
    private MenuMapper mapper;
    public void create(DataHandle<MenuDto, ?> handle) {
        MenuDto params = handle.getParams();
        Menu menu = new Menu();
        Date now = new Date();
        // 继续校验
        // ✔ 1. action 如果不是空就不能重复
        // ✔ 2. appid 需要在apps 表中
        // ✔ 3. parentid 如果不是0则必须存在相应数据
        // ✔ 4. 如果关联功能组
        boolean doUpdate = true;
        long  idCount;
        MPJLambdaWrapper<Menu> actionQuery = new MPJLambdaWrapper<>();
        if(params.getId() == null || params.getId() == 0) {
            doUpdate = false;
            menu.setCreatedAt(now);
        }else{
            idCount = mapper.selectCount(new LambdaQueryWrapper<Menu>().eq(Menu::getId, params.getId()));
            if(idCount == 0){
                handle.failure("id", "指定菜单不存在或已删除");
                return;
            }
            menu.setId(params.getId());
            actionQuery.ne("id", params.getId());
        }

        if(params.getAction() != null) {
            if(mapper.selectCount(actionQuery.eq(Menu::getAction, params.getAction())) > 0){
                handle.failure("action",  "路径已经存在");
                return;
            }
        }

        if(JoinWrappers.lambda(App.class).eq(App::getId, params.getAppId()).count() == 0){
            handle.failure("appId", "指定应用不存在");
            return;
        }

        if(params.getParentId() != null &&  params.getParentId() != 0) {
            MPJLambdaWrapper<Menu> parentQuery = new MPJLambdaWrapper<>();
            parentQuery.eq(Menu::getId, params.getParentId());
            // .eq(Menu::getParentId, 0); // 限制二级
            if(mapper.selectCount(parentQuery) == 0){
                handle.failure("parentId", "上级菜单不存在或已删除");
                return;
            }
        }

        if(params.getGroupId() != null && params.getGroupId() != 0){
            if(JoinWrappers.lambda(PermsGroup.class)
                    .eq(PermsGroup::getId, params.getGroupId())
                    .count() == 0){
                handle.failure("groupId", "关联接口功能组不存在");
                return;
            }
        }

        menu.setAction(params.getAction());
        menu.setName(params.getName());
        menu.setAppId(params.getAppId());
        menu.setParentId(params.getParentId());
        menu.setIcon(params.getIcon());
        menu.setDisplay(params.getDisplay());
        menu.setDetail(params.getDetail());
        menu.setGroupId(params.getGroupId());
        menu.setUpdatedAt(now);

        if(doUpdate){
            mapper.updateById(menu);
        }else{
            mapper.insert(menu);
        }
        handle.success();
    }

    public void remove(DataHandle<MenuDto, Object> handle) {
        MenuDto params = handle.getParams();
        if(JoinWrappers.lambda(Menu.class)
                .in(Menu::getId, params.getIds())
                .count() != params.getIds().size()){
            handle.failure("ids", "选择了无效的菜单");
            return;
        }
        mapper.deleteBatchIds(params.getIds());
        handle.success();
    }

    public void query(DataHandle<MenuDto, Object> handle) {
        MenuDto params = handle.getParams();

        MPJLambdaWrapper<Menu> query = new MPJLambdaWrapper<>("Me");
        query.selectAs(Menu::getId, MenuQueryVo::getMId)
                .selectAll(Menu.class)
                .selectAs(App::getName, MenuQueryVo::getAppName)
                .selectAs(PermsGroup::getName, MenuQueryVo::getGroupName)
                .innerJoin(Menu.class, "M", on -> on.and(build ->{
                    build.eq("Me", Menu::getId, "M", Menu::getParentId)
                            .or()
                            .eq("Me", Menu::getId, "M", Menu::getId);
                })).leftJoin(App.class, App::getId, "M", Menu::getAppId)
                .leftJoin(PermsGroup.class, PermsGroup::getId, "M", Menu::getGroupId)
                .eq(Menu::getParentId, 0)
                .orderByAsc(Menu::getAppId)
                .orderByDesc(Menu::getSort)
                .orderByAsc( "CASE WHEN M.parent_id = 0 THEN 0 ELSE 1 END")
                .orderByDesc("M", Menu::getSort);

        if(params.getAction() != null && !params.getAction().isEmpty()){
            query.eq("M", Menu::getAction, params.getAction());
        }

        if(params.getName() != null && !params.getName().isEmpty()){
            query.like("M", Menu::getName, "%" + params.getName() + "%");
        }

        if(params.getDisplay() != null){
            query.eq("M", Menu::getDisplay, params.getDisplay());
        }

        if(params.getAppId() != null && params.getAppId() != 0){
            query.eq("M", Menu::getAppId, params.getAppId());
        }

        if(params.getGroupId() != null && params.getGroupId() != 0){
            query.eq("M", Menu::getGroupId, params.getGroupId());
        }

        IPage<MenuQueryVo> page = mapper.selectJoinPage(
                new Page<>(params.getCurrent(), params.getSize()),
                MenuQueryVo.class,
                query);
        handle.success(page);
    }

    public void fetch(DataHandle<MenuDto, MenuFetchVo> handle) {
        MenuDto params = handle.getParams();
        MenuFetchVo vo = JoinWrappers.lambda(Menu.class)
                .selectAll()
                .eq(Menu::getId, params.getId())
                .one(MenuFetchVo.class);
        if(vo == null){
            handle.failure("id", "指定菜单不存在");
            return ;
        }
        handle.success(vo);
    }



}
